<?php
class ValidationCode
{
    private $width;  //验证码宽度
    private $height;  //验证码高度
    private $codeNum;  //验证码字符个数
    private $image; //图像资源
    private $disturbColorNum; //干扰元素的个数
    private $checkCode; //验证码的字符个数
    private $type; //验证码显示是小写字母还是大写字母……

    /**
        * 构造函数
        * @param $width : 图片宽度
        * @param $height : 图片高度
        * @param $codeNum : 验证码个数
        * @param $type : 0,纯数字; 1: 数字+小写字母 2: 数字+大小写字母
     **/
    public function __construct($width = 100, $height = 40, $codeNum = 4, $type = 2) 
    {
        $this->width = $width;
        $this->height = $height;
        $this->codeNum = $codeNum; 
        $this->type = $type;
        $this->checkCode = $this->createCheckCode();   //调用产生随机字符的函数

        //通过用户传过来的长度和宽度，确定要有多少个干扰点, 不会因为面积变小点的数量增多，或面积变大点的数量变少
        $number = floor($width * $height / 10);  //干扰点也有一定的限制，每10个像素一个干扰点
        if ($number > 240)  //240 来算
        {
            $this->disturbColorNum = 240 - $codeNum; //减去字符数，最多也就这么多干扰点
        }
        else
        {
            $this->disturbColorNum = $number;
        }
       
    }

    /**
     * 通过访问该方法输出图片到页面中
     **/
    public function showImage($fontFace = '')
    {
        //step 1,创建图像背景
        $this->createImage();
        //step 2，设置干扰元素
        $this->setDisturbColor();
        //step 3，向图像中随机画出文本
        $this->outputText($fontFace);
        //step 4，输出图像到浏览器
        $this->outputImage();

    }

    /**
     * 通过调用该方法调用随机的验证码字符串
     **/
    public function getCheckCode()
    {
        return $this->checkCode;
    }

    /**
     * 创建背景
     **/
    private function createImage()
    {
        //创建图像资源
        $this->image = imagecreatetruecolor($this->width, $this->height);
        //创建背景颜色
        $backColor = imagecolorallocate($this->image, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255));  //随机创建浅色背景
        //imagecreatetruecolor()创建的背景,需要用imagefill()填充予以背景色
        imagefill($this->image, 0, 0, $backColor); 
        //为我们的背景图片加个边框, 其中边框也有1个像素，所以减1也
        $border = imagecolorallocate($this->image, 0, 0, 0);
        imagerectangle($this->image, 0, 0, $this->width - 1, $this->height - 1, $border);
    } 

    /**
     * 设置干扰元素
     **/
    private function setDisturbColor()
    {
        //画100个点
        for ($i = 0; $i < $this->disturbColorNum; $i++) 
        {
            //点的随机颜色
            $pixColor = imagecolorallocate($this->image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
            //因为其上有个边框，所以要减2
            imagesetpixel($this->image, mt_rand(1, $this->width-2), mt_rand(1, $this->height-2), $pixColor);
        } 
        //画10个曲线，曲线的中心可以在图像之外
        for ($i = 0; $i < 10; $i++)
        {
            //弧线的颜色
            $arcColor = imagecolorallocate($this->image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
            //x轴取负数，画的曲线更有突兀的感觉
            imagearc($this->image, mt_rand(-10, $this->width), mt_rand(-10, $this->height), 
                 mt_rand(30, 300), mt_rand(20, 200), 55, 44, $arcColor);
        }
    }
    /**
     * 生成随机字符串
     **/
    private function createCheckCode()
    {
        // 0 o O l 1  这几个容易混淆的字母去掉
        $code = '23456789abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ'; 
        $t = array(9, 35, strlen($code)-1);
        $str = '';
        for ($i = 0; $i < $this->codeNum; $i++)
        {
            $char = $code[mt_rand(0, $t[$this->type])];   //$this->type对应于$t数组中的数值
            $str .= $char;
        }
        return $str;
    }
    /**
     * 向图像中随机画出文本
     **/
    private function outputText($fontFace = '')   //函数参数设为空
    {
        for ($i = 0; $i < $this->codeNum; $i++)
        {
            $fontColor = imagecolorallocate($this->image, mt_rand(0, 128), mt_rand(0, 128), mt_rand(0, 128)); //0-128 让颜色变深
            if (!empty($fontFace)) //看一下字体是否为空
            {
                //有自定义字体
                $fontSize = mt_rand(18, 20);
                //宽度减8，离右边8像素，不会倾斜出去，加8，离左边也是8个像素
                $x = floor(($this->width-8) / $this->codeNum) * $i + 8;
                $y = mt_rand($fontSize+5, $this->height-10); //设置基线的位置
                imagettftext($this->image, $fontSize, mt_rand(-45, 45), $x, $y, $fontColor, $fontFace, $this->checkCode[$i]);
            }
            else
            {
                //$fontSize = mt_rand(2, 5);  //随机字体
                $fontSize = 5;                //由于设成随机字体显示效果太小了，就直接给最大字体吧
                $x = floor($this->width / $this->codeNum) * $i + 8;  //如width:100 100/4 = 25 ,加了8个像素是$i为0时，别挨边画
                $y = mt_rand(0, $this->height - imagefontheight($fontSize));  //减去字体的高度，以防止画到外面去了
                    /*
                    * |---------------|
                    * |               |减去字体高度后，就会防止字体画出图形外面了
                    * |---------------|
                    * |---------------|
                    **/
                imagechar($this->image, $fontSize, $x, $y, $this->checkCode[$i], $fontColor);
            }
            
        }
    }

    /**
     * 输出图像到浏览器
     **/
    private function outputImage()
    {
        if (imagetypes() & IMG_PNG)  //png格式排在前面，图片默认格式
        {
            //png support is enabled
            header('Content-Type:image/png');
            imagepng($this->image);
        }
        else if (imagetypes() & IMG_JPG)
        {
            //jpg support is enabled
            header('Content-Type:image/jpeg');
            imagejpeg($this->image);
        }
        else if (imagetypes() & IMG_GIF)
        {
            //gif support is enabled
            header('Content-Type:image/gif');
            imagegif($this->image);
        }
        else if (imagetypes() & IMG_WBMP)
        {
            header('Content-Type:image/vnd.wap.wbmp');
            imagewbmp($this->image);

        }
        else
        {
            die('PHP不支持创建图像！');
        }
    }
    
    /**
     * 定义析构方法自动销毁图像资源
     **/
    public function __destruct()
    {
        imagedestroy($this->image);
    }

}
?>
